﻿//
// Copyright (c) 2011 HyperCrunch, Inc. http://www.hypercrunch.com 
// Author: Nik Kalyani  http://www.kalyani.com (Twitter: @techbubble)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Security.Permissions;
using DotNetNuke.UI;

using DotNetNuke.Entities.Content.Common;
using DotNetNuke.Entities.Content.Taxonomy;
using DotNetNuke.Entities.Content;
using DotNetNuke.Entities.Users;
using DotNetNuke.Services.Authentication;
using DotNetNuke.Security.Membership;
using DotNetNuke.Security;

namespace HyperCrunch.Druid.Mobile
{
    public class SiteController : AppControllerBase
    {
        public static Dictionary<string, List<ModuleInfo>> GetContent(UIContext uiContext, string vocabularyName)
        {
            return String.IsNullOrEmpty(vocabularyName) ? GetTopLevelContent(uiContext) : GetTaggedContent(vocabularyName, uiContext);
        }

        public static string GetView(UIContext uiContext)
        {
            string view = String.Empty;

            // Look for script first in the portal home folder, then in the Host folder
            // If neither is found, extract from assembly to the Host folder and use

            // Home folder search
            string viewFolder = uiContext.PortalSettings.HomeDirectoryMapPath + "mobile\\";
            string viewPath = viewFolder + Globals.RAZOR_MOBILE_SITE_VIEW;
            if (File.Exists(viewPath))
                view = File.ReadAllText(viewPath);

            // Host folder search
            if (String.IsNullOrEmpty(view))
            {
                viewFolder = uiContext.Context.Server.MapPath("~/Portals/_default/mobile/");
                viewPath = viewFolder + Globals.RAZOR_MOBILE_SITE_VIEW;
                if (File.Exists(viewPath))
                    view = File.ReadAllText(viewPath);
            }

            // Extract from assembly to Host folder
            if (String.IsNullOrEmpty(view))
            {
                if (!Directory.Exists(viewFolder)) Directory.CreateDirectory(viewFolder);
                try
                {
                    string resource = "HyperCrunch.Druid.Mobile.assets." + Globals.RAZOR_MOBILE_SITE_VIEW;
                    using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        view = reader.ReadToEnd();
                    } 
                    File.WriteAllText(viewPath, view);
                }
                catch
                {
                }
            }

            return view;
        }

        public static string GetAssetUrl(UIContext uiContext, string assetFile)
        {
            string assetUrl = String.Empty;

            // Home folder search
            string assetFolder = uiContext.PortalSettings.HomeDirectoryMapPath + "mobile\\";
            string assetPath = assetFolder + assetFile;
            if (File.Exists(assetPath))
                assetUrl = uiContext.PortalSettings.HomeDirectory + "mobile/" + assetFile;

            // Host folder search
            if (String.IsNullOrEmpty(assetUrl))
            {
                assetFolder = uiContext.Context.Server.MapPath("~/Portals/_default/mobile/");
                assetPath = assetFolder + assetFile;
                if (File.Exists(assetPath))
                    assetUrl = (uiContext.Context.Request.ApplicationPath + "/Portals/_default/mobile/" + assetFile).Replace("//", "/");
            }

            // Extract from assembly to Host folder
            if (String.IsNullOrEmpty(assetUrl))
            {
                if (!Directory.Exists(assetFolder)) Directory.CreateDirectory(assetFolder);
                try
                {
                    string assetContent = String.Empty;
                    string resource = "HyperCrunch.Druid.Mobile.assets." + assetFile;
                    using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        assetContent = reader.ReadToEnd();
                    }
                    File.WriteAllText(assetPath, assetContent);
                    assetUrl = (uiContext.Context.Request.ApplicationPath + "/Portals/_default/mobile/" + assetFile).Replace("//", "/");
                }
                catch
                {
                }
            }

            return assetUrl;
        }
        #region Navigation rendering
        /// <summary>
        /// Enumerates the top-level pages of a site and returns a list of these pages
        /// along with the modules on each of the pages to which the current user has access.
        /// </summary>
        /// <param name="portalSettings"></param>
        /// <returns></returns>
        private static Dictionary<string, List<ModuleInfo>> GetTopLevelContent(UIContext uiContext)
        {
            ModuleController moduleController = new ModuleController();
            Dictionary<string, List<ModuleInfo>> navContent = new Dictionary<string, List<ModuleInfo>>();
            List<TabInfo> portalTabs = TabController.GetTabsBySortOrder(uiContext.PortalSettings.PortalId, PortalController.GetActivePortalLanguage(uiContext.PortalSettings.PortalId), false);

            foreach (TabInfo tabInfo in portalTabs)
            {
                if ((tabInfo.Level == 0) && (tabInfo.TabName.ToLower() != "admin") && (Navigation.CanShowTab(tabInfo, false, false)))
                {
                    Dictionary<int, ModuleInfo> tabModules = moduleController.GetTabModules(tabInfo.TabID);
                    int moduleCount = tabModules == null ? 0 : tabModules.Count;
                    if (moduleCount > 0)
                    {
                        List<ModuleInfo> tabModuleList = new List<ModuleInfo>();
                        foreach (int index in tabModules.Keys)
                        {
                            ModuleInfo moduleInfo = tabModules[index];                            
                            if (ModulePermissionController.CanViewModule(moduleInfo) && !moduleInfo.IsDeleted)
                            {
                                //  if (moduleInfo.StartDate < DateTime.Now && moduleInfo.EndDate > DateTime.Now)
                                {
                                    ModuleMetaInfo moduleMetaInfo = ModuleMetaInfo.Instance(moduleInfo, uiContext);
                                    RenderableType renderableType = RenderableType.None;
                                    if (Utility.IsMobileRenderable(moduleInfo, moduleMetaInfo, uiContext))
                                        renderableType = RenderableType.Mobile;
                                    else if (Utility.IsDefaultRenderable(moduleInfo))
                                        renderableType = RenderableType.Default;

                                    if (renderableType != RenderableType.None)
                                    {
                                        moduleInfo.DesktopModule.SupportedFeatures = (int) renderableType;
                                        tabModuleList.Add(moduleInfo);
                                    }
                                }
                            }
                        }

                        if (tabModuleList.Count > 0)
                        {
                            string key = String.IsNullOrEmpty(tabInfo.Title) ? tabInfo.TabName : tabInfo.Title;
                            if (navContent.ContainsKey(key)) key = key + DateTime.Now.AddSeconds(1).ToString() + navContent.Count.ToString();
                            navContent.Add(key, tabModuleList);
                        }
                    }
                }
            }

            return navContent;
        }

        /// <summary>
        /// Enumerates all the terms for a vocabulary. For each term, a list of modules tagged with
        /// the term to which the user has access is returned.
        /// </summary>
        /// <param name="vocabularyName"></param>
        /// <param name="portalSettings"></param>
        /// <returns></returns>
        private static Dictionary<string, List<ModuleInfo>> GetTaggedContent(string vocabularyName, UIContext uiContext)
        {
            ModuleController moduleController = new ModuleController();
            var termController = Util.GetTermController();
            var contentController = Util.GetContentController();
            Dictionary<string, List<ModuleInfo>> navContent = new Dictionary<string, List<ModuleInfo>>();

            // Get all the terms for the selected Vocabulary
            IQueryable<Term> terms = termController.GetTermsByVocabulary(vocabularyName);

            // For each term, if there is a valid module, then add that term and module list to model
            foreach (Term term in terms)
            {
                IQueryable<ContentItem> contentItems = contentController.GetContentItemsByTerm(term.Name);
                List<ModuleInfo> termModuleList = new List<ModuleInfo>();
                foreach (ContentItem contentItem in contentItems)
                {
                    ModuleInfo moduleInfo = moduleController.GetModule(contentItem.ModuleID, contentItem.TabID);

                    if (ModulePermissionController.CanViewModule(moduleInfo) && !moduleInfo.IsDeleted)
                    {
                        //  if (moduleInfo.StartDate < DateTime.Now && moduleInfo.EndDate > DateTime.Now)
                        {
                            ModuleMetaInfo moduleMetaInfo = ModuleMetaInfo.Instance(moduleInfo, uiContext);
                            RenderableType renderableType = RenderableType.None;
                            if (Utility.IsMobileRenderable(moduleInfo, moduleMetaInfo, uiContext))
                                renderableType = RenderableType.Mobile;
                            else if (Utility.IsDefaultRenderable(moduleInfo))
                                renderableType = RenderableType.Default;

                            if (renderableType != RenderableType.None)
                            {
                                moduleInfo.DesktopModule.SupportedFeatures = (int)renderableType;
                                termModuleList.Add(moduleInfo);
                            }

                        }
                    }
                }

                if (termModuleList.Count > 0)
                    navContent.Add(term.Name, termModuleList);
            }

            return navContent;
        }
#endregion

        [RequestMethod(HttpVerbType.POST)]
        public ActionResult Login(UIContext uiContext, string username, string password, string returnUrl)
        {
            UserLoginStatus loginStatus = UserLoginStatus.LOGIN_FAILURE;
            UserInfo userInfo = UserController.ValidateUser(uiContext.PortalSettings.PortalId,
                                                            username,
                                                            password,
                                                            "DNN",
                                                            "",
                                                            uiContext.PortalSettings.PortalName,
                                                            AuthenticationLoginBase.GetIPAddress(),
                                                            ref loginStatus);

            if ((loginStatus == UserLoginStatus.LOGIN_SUCCESS) || (loginStatus == UserLoginStatus.LOGIN_SUPERUSER))
            {
                UserController.UserLogin
                (uiContext.PortalSettings.PortalId,
                userInfo, uiContext.PortalSettings.PortalName,
                uiContext.Context.Request.UserHostAddress, false);
                return new JsonResult { Serialize = false, Data = "{ \"message\" : \"\" }" };
            }
            else
                return new JsonResult { Serialize = false, Data = "{ \"message\" : \"" + loginStatus.ToString() + "\" }" };
        }

        [RequestMethod(HttpVerbType.GET)]
        public ActionResult Logout(UIContext uiContext)
        {
            if (uiContext.Context.Request.IsAuthenticated)
            {
				PortalSecurity portalSecurity = new PortalSecurity();
				portalSecurity.SignOut();
            }
            return new RedirectResult { Url = DotNetNuke.Common.Globals.NavigateURL(uiContext.PortalSettings.ActiveTab.TabID, "", new string[] { }) };
        }

        [RequestMethod(HttpVerbType.GET)]
        public ActionResult Content(UIContext uiContext, string id)
        {
            ModuleInfo moduleInfo = AppRenderer.GetModuleFromAUID(id);
            string content = String.Empty;
            if (moduleInfo != null)
            {
                object bizController = Utility.GetModuleBusinessController(moduleInfo);
                return AppRenderer.GetAppSearchContent(moduleInfo, uiContext, bizController);
            }            
            else
                return new ContentResult { Content = content };
        }

    }
}
